﻿using BigMonitoringWarningApi.Tool.Extension;
using GYCTOAManagementSystemNewApi.Model.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;

namespace GYCTOAManagementSystemNewApi.Tool
{
    /// <summary>
    /// 树结构帮助类
    /// </summary>
    public static class TreeHelper
    {
        /// <summary>
        /// 建造树结构
        /// </summary>
        /// <param name="allNodes">所有的节点</param>
        /// <param name="IsSortAsc">默认不排序,null=不排序, true=正序排序, false=倒叙排序</param>
        /// <param name="DefaultParentId">默认第一级ID</param>
        /// <param name="UseCopyChildren">(当子级目录符合条件下)使用副本孩子节点(一般不使用此字段)</param>
        /// <returns></returns>
        public static List<T> BuildTree<T>(this List<T> allNodes, bool? IsSortAsc = null, string DefaultParentId = "0", Func<T, bool> UseCopyChildren = null) where T : TreeModel, new()
        {
            List<T> resData = new List<T>();
            var rootNodes = allNodes.Where(x => x.OnlyParentId.ToString() == DefaultParentId || x.OnlyParentId.IsEmpty()).ToList();
            resData = rootNodes;
            resData.ForEach(aRootNode =>
            {
                if (HaveChildren(allNodes, aRootNode.OnlyId))
                {
                    var ChildrenList = GetChildren(allNodes, aRootNode, IsSortAsc, UseCopyChildren);
                    if (UseCopyChildren != null && !ChildrenList.IsEmpty() && !ChildrenList.OfType<T>().Where(UseCopyChildren).ToList().IsEmpty())
                    {
                        aRootNode.CopyChildren = ChildrenList;
                    }
                    else
                    {
                        aRootNode.OnlyChildren = ChildrenList;
                    }
                }
            });

            return resData;
        }

        /// <summary>
        /// 获取所有子节点
        /// </summary>
        /// <typeparam name="T">树模型（TreeModel或继承它的模型）</typeparam>
        /// <param name="nodes">所有节点列表</param>
        /// <param name="parentNode">父节点Id</param>
        /// <param name="IsSortAsc">是否排序</param>
        /// <param name="UseCopyChildren">什么情况下使用副本孩子节点</param>
        /// <returns></returns>
        private static List<object> GetChildren<T>(List<T> nodes, T parentNode, bool? IsSortAsc, Func<T, bool> UseCopyChildren = null) where T : TreeModel, new()
        {
            Type type = typeof(T);
            var properties = type.GetProperties().ToList();
            List<object> resData = new List<object>();
            var children = nodes.Where(x => x.OnlyParentId.Equals(parentNode.OnlyId));

            #region 处理排序
            if (IsSortAsc == true)
            {
                children = children.OrderBy(x => x.OnlySort).ToList();
            }
            else if (IsSortAsc == false)
            {
                children = children.OrderByDescending(x => x.OnlySort).ToList();
            }
            else
            {
                children = children.ToList();
            }
            #endregion

            foreach (var aChildren in children)
            {
                T newNode = new T();
                resData.Add(newNode);
                //赋值属性
                properties.ForEach(aProperty =>
                {
                    var value = aProperty.GetValue(aChildren, null);
                    aProperty.SetValue(newNode, value);
                });
                //设置深度
                newNode.OnlyLevel = parentNode.OnlyLevel + 1;

                if (HaveChildren(nodes, aChildren.OnlyId))
                {
                    var ChildrenList = GetChildren(nodes, newNode, IsSortAsc, UseCopyChildren);
                    if (UseCopyChildren != null && !ChildrenList.IsEmpty() && !ChildrenList.OfType<T>().Where(UseCopyChildren).ToList().IsEmpty())
                    {
                        newNode.CopyChildren = ChildrenList;
                    }
                    else
                    {
                        newNode.OnlyChildren = ChildrenList;
                    }
                }
            };
            return resData;
        }

        /// <summary>
        /// 判断当前节点是否有子节点
        /// </summary>
        /// <typeparam name="T">树模型</typeparam>
        /// <param name="nodes">所有节点</param>
        /// <param name="nodeId">当前节点Id</param>
        /// <returns></returns>
        private static bool HaveChildren<T>(List<T> nodes, object nodeId) where T : TreeModel, new()
        {
            return nodes.Exists(x => x.OnlyParentId.Equals(nodeId));
        }
    }
}
